package main

import "fmt"

/**
代理模式原理详细解释：
代理模式（Proxy Pattern）是一种结构型设计模式，
通过引入一个 【代理对象】，控制对【真实对象】的访问。

【代理对象】 和 【真实对象】实现相同的接口，客户端通过代理对象来访问真实对象，从而可以在访问前后进行一些额外的操作。

代理模式的核心思想是通过一个 【代理对象】 来控制对真实对象的访问。
【代理对象】在 【客户端】和【真实对象】之间起到了中介的作用，
【客户端】通过【代理对象】来间接访问【真实对象】。
【代理对象】可以对【真实对象】的访问进行控制，例如，可以在访问前后执行一些附加操作，如权限验证、缓存、日志记录等。

总结：
1.能通过代理对象，控制客户端不要直接访问真实对象
2.通过代理，实现堆真实对象方法的增强

使用场景解释：
代理模式适用于以下场景：
    1.当需要对真实对象的访问进行控制，并在访问前后执行一些额外的操作时，可以使用代理模式。代理对象可以在访问前后进行权限验证、缓存、日志记录等操作。
    2.当需要在不修改真实对象的情况下，对其进行扩展或修改时，可以使用代理模式。代理对象可以继承真实对象的接口，并在其基础上增加额外的功能。
    3.当真实对象由于某些原因无法直接访问时，可以使用代理模式。代理对象可以在访问真实对象之前进行一些准备工作，如网络连接、初始化等。
*/

// Subject 接口
type Subject interface {
	Request()
}

// RealSubject 真实对象
type RealSubject struct{}

// Request 真实对象的请求
func (r *RealSubject) Request() {
	fmt.Println("RealSubject: Handling request")
}

// Proxy 代理对象
type Proxy struct {
	realSubject *RealSubject //将真实类作为自己的属性
}

// Request 代理对象的请求   代理对象不仅提供了真实类的方法，还在调用该方法的前后，调用自己的增强方法
func (p *Proxy) Request() {
	if p.realSubject == nil {
		p.realSubject = &RealSubject{}
	}

	p.preRequest()
	p.realSubject.Request()
	p.postRequest()
}

func (p *Proxy) preRequest() {
	fmt.Println("Proxy: Preparing request")
}

func (p *Proxy) postRequest() {
	fmt.Println("Proxy: Finishing request")
}

func main() {
	proxy := &Proxy{}
	proxy.Request()
}
